#include "StdAfx.h"
#include "MFCD3D11Test.h"
#include "RenderSphere.h"
#include "Utility/D3D/D3DUtilityFunction.h"

// CRenderWnd
IMPLEMENT_DYNAMIC(CRenderSphere, CD3DWnd)

CRenderSphere::CRenderSphere(void):m_pVB(NULL),m_pIB(NULL),m_pInputLayout(NULL),m_fRadius(1.0f),m_uSlices(44),m_uStacks(44),
m_iNumVertices(0),m_iNumIndices(0),m_pEffect(NULL),m_pDirectoryUtil(NULL)
{
	InitVariable();
}


CRenderSphere::~CRenderSphere(void)
{
	OnDestroyResouce();
	SAFE_DELETE(m_pDirectoryUtil);
}

void CRenderSphere::InitVariable()
{
	if(m_pDirectoryUtil)
		SAFE_DELETE(m_pDirectoryUtil);
	m_pDirectoryUtil = new CDirectoryUtil();

	TCHAR Dir[MAX_PATH];
	ZeroMemory(Dir, sizeof(TCHAR)*MAX_PATH);
	
	GetModuleFileName(NULL, Dir, MAX_PATH);
	CString strDir(Dir);
	int iPos = strDir.Find('\\');
	int iPos1 = strDir.Find('\\',iPos+1);
	CString strDir1 = strDir.Left(iPos1);
	CString strDir2 = strDir.Mid(iPos,iPos1-iPos);
	strDir1 += strDir2;
	
	m_pDirectoryUtil->initSubDirectory(strDir1.GetBuffer());
}

HRESULT CRenderSphere::OnCreateResource(ID3D11Device* pd3dDevice)
{
	HRESULT hr = S_OK;
	//recreate directory
	InitVariable();
	//Create sphere geometry
	V(CD3DUtilityFunction::CreateAssistSphere(pd3dDevice,m_fRadius,m_uSlices,m_uStacks,&m_pVB,&m_pIB,&m_iNumVertices,&m_iNumIndices));
	//create effects
	TCHAR ShaderFileDir[MAX_PATH];
	enum SUBDIRECTORY subfolder = SUBDIRECTORY::SHADERSDIR;
	m_pDirectoryUtil->GetAbsoluteFileFolder(L"RenderSphere.fx",subfolder, ShaderFileDir);
	hr = CD3DUtilityFunction::CreateEffectsFromFile(pd3dDevice, ShaderFileDir, NULL, "fx_5_0", &m_pEffect);	
	ID3DX11EffectTechnique* pRenderTech = m_pEffect->GetTechniqueByName("RenderSphereTech");
	//create vertex layout
	const D3D11_INPUT_ELEMENT_DESC s_ShapeLayout[] =
	{
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	};
	hr = CD3DUtilityFunction::CreateVertexLayout(pd3dDevice,s_ShapeLayout, ARRAYSIZE(s_ShapeLayout), pRenderTech, &m_pInputLayout);

	// Setup the camera's view parameters
	D3DXVECTOR3 vecEye( 0.0f, 0.0f, -4.0f );
	D3DXVECTOR3 vecAt ( 0.0f, 0.0f, -0.0f );
	m_modelViewCamera.SetViewParams( &vecEye, &vecAt );

	return hr;
}

HRESULT CRenderSphere::OnSwapChainResize(ID3D11Device* pd3dDevice, IDXGISwapChain* pSwapChain, 
	const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc)
{
	// Setup the camera's projection parameters
	float fAspectRatio = pBackBufferSurfaceDesc->Width / ( FLOAT )pBackBufferSurfaceDesc->Height;
	m_modelViewCamera.SetProjParams( D3DX_PI / 4, fAspectRatio, 0.001f, 10000.0f );
	m_modelViewCamera.SetWindow( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height );
	m_modelViewCamera.SetButtonMasks( MOUSE_LEFT_BUTTON, MOUSE_WHEEL, MOUSE_RIGHT_BUTTON );
	return S_OK;
}

void CRenderSphere::OnRender(ID3D11Device* pd3dDevice,ID3D11DeviceContext* pd3dImmediateContext, double fTime, float fElapsedTime)
{
	if(!m_pVB || !m_pIB)
		return;

	HRESULT hr = S_OK;
	// Set vertex buffer	
	// Get the projection & view matrix from the camera class
	D3DXMATRIX mWorld = *(m_modelViewCamera.GetWorldMatrix());
	D3DXMATRIX mView = *(m_modelViewCamera.GetViewMatrix());
	D3DXMATRIX mProj = *(m_modelViewCamera.GetProjMatrix());
	D3DXMATRIX mWorldViewProjection = mWorld * mView * mProj;

	V(m_pEffect->GetVariableByName("mWorld")->AsMatrix()->SetMatrix((float*)(&mWorld)));
	V(m_pEffect->GetVariableByName("mWorldViewProjection")->AsMatrix()->SetMatrix((float*)(&mWorldViewProjection)));

	D3DXVECTOR3 vLightPt = *(m_modelViewCamera.GetEyePt());
	V(m_pEffect->GetVariableByName("vLightPt")->AsVector()->SetFloatVector((float*)(&vLightPt)));

	// Set render resources
	pd3dImmediateContext->IASetInputLayout( m_pInputLayout );
	ID3D11Buffer* pVB[1] = { m_pVB };
	UINT pStride[1] = { sizeof(VertexType_POSNORM) };
	UINT pOffset[1] = { 0 };
	pd3dImmediateContext->IASetVertexBuffers( 0, 1, pVB, pStride, pOffset );
	pd3dImmediateContext->IASetIndexBuffer(m_pIB, DXGI_FORMAT_R16_UINT, 0);
	pd3dImmediateContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

	// Render objects here...
	// Apply the technique contained in the effect 
	D3DX11_TECHNIQUE_DESC Desc;
	ID3DX11EffectTechnique* pRenderTech = m_pEffect->GetTechniqueByName("RenderSphereTech");
	pRenderTech->GetDesc( &Desc );

	for( UINT iPass = 0; iPass < Desc.Passes; iPass++ )
	{
		pRenderTech->GetPassByIndex( iPass )->Apply( 0, pd3dImmediateContext );
		pd3dImmediateContext->DrawIndexed(m_iNumIndices,0,0);				
	}

}

void CRenderSphere::OnFrameMove(double fTime, float fElapsedTime)
{
	m_modelViewCamera.FrameMove(fElapsedTime);
}

void CRenderSphere::OnReleasingSwapChain()
{
	CD3DWnd::OnReleasingSwapChain();
}

void CRenderSphere::OnDestroyResouce()
{
	SAFE_RELEASE(m_pVB);
	SAFE_RELEASE(m_pIB);
	SAFE_RELEASE(m_pInputLayout);
	SAFE_RELEASE(m_pEffect);
	CD3DWnd::OnDestroyResouce();
}

BEGIN_MESSAGE_MAP(CRenderSphere, CD3DWnd)
END_MESSAGE_MAP()


BOOL CRenderSphere::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
	// TODO: Add your specialized code here and/or call the base class
	m_modelViewCamera.HandleMessages(GetSafeHwnd(),message,wParam,lParam);

	switch(message)
	{
	case WM_KEYDOWN:
	case WM_KEYUP:
	case WM_RBUTTONDOWN:
	case WM_MBUTTONDOWN:
	case WM_LBUTTONDOWN:
	case WM_RBUTTONDBLCLK:
	case WM_MBUTTONDBLCLK:
	case WM_LBUTTONDBLCLK:
	case WM_RBUTTONUP:
	case WM_MBUTTONUP:
	case WM_LBUTTONUP:
	case WM_CAPTURECHANGED:
	case WM_MOUSEWHEEL:
	case WM_MOUSEMOVE:
		{
			/*GetParent()->*/PostMessage(WM_RENDER);
			//theApp.OutputString(_T("test small window"));
		}
	}
	return CD3DWnd::OnWndMsg(message, wParam, lParam, pResult);
}
